package com.shuwen.gcdj.service.role;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shuwen.gcdj.bean.rolepower.response.ButtonPowerResp;
import com.shuwen.gcdj.bean.rolepower.response.PowerLevelResp;
import com.shuwen.gcdj.common.exception.ApiException;
import com.shuwen.gcdj.bean.power.response.SelectedRolePowerItemResp;
import com.shuwen.gcdj.bean.role.request.MultiBindRolePowerReq;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.common.constant.RolePowerCst;
import com.shuwen.gcdj.common.enums.ErrorCode;
import com.shuwen.gcdj.common.util.BeanHelper;
import com.shuwen.gcdj.common.util.account.AccountUtil;
import com.shuwen.gcdj.dto.account.InitUserDto;
import com.shuwen.gcdj.dto.role.SearchRolePowerDto;
import com.shuwen.gcdj.entity.PowerAuthDept;
import com.shuwen.gcdj.entity.Role;
import com.shuwen.gcdj.entity.RolePower;
import com.shuwen.gcdj.exception.IErrorCodeFactory;
import com.shuwen.gcdj.mapper.mysql.PowerAuthDeptMapper;
import com.shuwen.gcdj.mapper.mysql.PowerMapper;
import com.shuwen.gcdj.mapper.mysql.RoleMapper;
import com.shuwen.gcdj.mapper.mysql.RolePowerMapper;
import com.shuwen.gcdj.service.BaseService;
import com.shuwen.gcdj.service.redis.RedisService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
@Slf4j
public class RolePowerService extends BaseService<RolePowerMapper, RolePower> {

    private final RolePowerMapper rolePowerMapper;
    private final RoleMapper roleMapper;
    private final PowerAuthDeptMapper powerAuthDeptMapper;
    private final RedisService redisService;
    private final PowerMapper powerMapper;

    /**
     * 获取权限码对应的记录
     *
     * @param dto SearchRolePowerDto
     * @return List<RolePower>
     */
    public List<RolePower> searchList(SearchRolePowerDto dto) {
        return rolePowerMapper.selectList(buildQueryWrapper(dto));
    }

    /**
     * 检查是否存在
     *
     * @param dto SearchRolePowerDto
     * @return boolean
     */
    public boolean checkExist(SearchRolePowerDto dto) {
        Integer c = rolePowerMapper.selectCount(buildQueryWrapper(dto));
        return c != null && c >= 1;
    }

    /**
     * 删除角色权限关系
     *
     * @param dto         SearchRolePowerDto
     * @param initUserDto InitUserDto
     */
    public void deleteRolePower(SearchRolePowerDto dto, InitUserDto initUserDto) {
        if (dto == null) {
            return;
        }

        if ((dto.getRoleIds() == null || dto.getRoleIds().isEmpty()) && (dto.getPowerCodes() == null || dto.getPowerCodes().isEmpty())) {
            throw new ApiException("解除角色权限关系参数错误，不能清空角色权限配置");
        }
        QueryWrapper<RolePower> q = buildQueryWrapper(dto);
        List<RolePower> rs = rolePowerMapper.selectList(q);
        cleanBindRolePowerWithRolePowerList(rs);

        // 清空用户角色缓存 + 权限缓存
        redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
        redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));
    }

    /**
     * 批量替换权限码
     *
     * @param powerCode    String
     * @param newPowerCode String
     */
    public void replacePowerCode(String powerCode, String newPowerCode) {
        if (powerCode != null && !powerCode.isEmpty() && newPowerCode != null && !newPowerCode.isEmpty()) {
            QueryWrapper<RolePower> qw = new QueryWrapper<>();
            qw.eq("`power_code`", powerCode);
            qw.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
            List<RolePower> rws = rolePowerMapper.selectList(qw);
            if (rws != null) {
                for (RolePower rw : rws) {
                    rw.setPowerCode(newPowerCode);
                }
                updateBatchById(rws);
            }

            // 清空用户角色缓存 + 权限缓存
            redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
            redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));
        }
    }

    /**
     * 批量绑定角色权限码
     *
     * @param req         MultiBindRolePowerReq
     * @param initUserDto InitUserDto
     */
    public void bindRolePowerMulti(MultiBindRolePowerReq req, InitUserDto initUserDto) {
        // check bind
        checkBindRolePowerMulti(req, initUserDto);

        // clean bind relation
        cleanBindRolePower(req.getRoleId(), req.getType());

        // 清空用户角色缓存 + 权限缓存
        redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
        redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));

        // bind
        bindRolePowerAction(req, initUserDto);
    }

    /**
     * 根据角色获取权限配置
     *
     * @param roleId String
     * @return List<PowerItemResp>
     */
    public List<PowerLevelResp> getPowersByRoleId(String roleId) {
        if (StringUtils.isEmpty(roleId)) {
            return new ArrayList<>();
        }

        Role role = roleMapper.selectById(roleId);
        if (role == null) {
            throw new ApiException(IErrorCodeFactory.create(ErrorCode.DATA_NOT_EXIST.getCode(), "角色[" + roleId + "]不存在"));
        }

        List<PowerLevelResp> items;

        if (role.getCode() != null && role.getCode().equals(RolePowerCst.ROLE_CODE_SUPER)) {
            // 超级管理员返回所有
            List<SelectedRolePowerItemResp> superSelectedRolePowers = rolePowerMapper.getSuperSelectedRolePowers();
            List<PowerLevelResp> powerLevelRespList = getPowerLevelRespList(superSelectedRolePowers);
            items = powerLevelRespList;

        } else {
            // 递归查询角色拥有的权限
            List<SelectedRolePowerItemResp> powersByRoleId = rolePowerMapper.getPowersByRoleId(roleId);
            List<PowerLevelResp> powerLevelRespList = getPowerLevelRespList(powersByRoleId);
            items = powerLevelRespList;
        }

        if (CollectionUtils.isEmpty(items)) {
            return items;
        }

        return items;
    }

    //获取角色拥有的菜单和权限
    public List<PowerLevelResp> getPowerLevelRespList(List<SelectedRolePowerItemResp> powersByRoleId) {
        //装role拥有的powerId
        List<String> powerIdList = new ArrayList<>();
        for (SelectedRolePowerItemResp selectedRolePowerItemResp : powersByRoleId) {
            powerIdList.add(selectedRolePowerItemResp.getId());
        }
        //要返回的结果集
        List<PowerLevelResp> powers = new ArrayList<>();
        //获取所有权限
        List<PowerLevelResp> list = roleMapper.getListByparent();
        //存放一级目录
        for (PowerLevelResp powerLevelResp : list) {
            if (powerIdList.contains(powerLevelResp.getId())) {
                powerLevelResp.setChecked(0);
            } else {
                powerLevelResp.setChecked(1);
            }
            powers.add(powerLevelResp);
        }
        //开始递归
        /*for (PowerLevelResp power : powers) {
            List<PowerLevelResp> pList = getRoleByChild(power.getId(), list, powerIdList);
            power.setChildren(pList);
        }*/
        List<PowerLevelResp> parents = powers.stream().filter(x->x.getParentId().equals("0") && x.getLevel().equals(1)).collect(Collectors.toList());
        List<PowerLevelResp> resp = new ArrayList<>();
        resp = powerLevelListToTree(powers,parents);
        return resp;
    }

    // 检查角色权限绑定
    private void checkBindRolePowerMulti(MultiBindRolePowerReq req, InitUserDto initUserDto) {
        if (req == null) {
            throw new ApiException("绑定角色权限参数错误");
        }

        if (StringUtils.isEmpty(req.getRoleId())) {
            throw new ApiException("绑定角色id参数不能为空");
        }
        if (StringUtils.isEmpty(req.getType())) {
            throw new ApiException("type参数不能为空");
        }

        Role role = roleMapper.selectById(req.getRoleId());
        if (role == null) {
            throw new ApiException("绑定角色不存在");
        }

        // super user forbidden update
        if (role.getCode() != null
                && role.getCode().equals(RolePowerCst.ROLE_CODE_SUPER)
                && initUserDto != null
                && !initUserDto.getLoginName().equals(RolePowerCst.SUPER_LOGIN_NAME)) {
            throw new ApiException(IErrorCodeFactory.create(ErrorCode.FORBIDDEN.getCode(), "超级管理员角色权限不允许修改"));
        }

        for (String s : req.getPowers()) {
            if (StringUtils.isEmpty(s)) {
                throw new ApiException("绑定权限码不能为空");
            }
        }
    }

    /**
     * 清除角色权限配置 + 授权部门
     *
     * @param roleId String
     */
    private void cleanBindRolePower(String roleId, Integer type) {
//        SearchRolePowerDto dto = new SearchRolePowerDto();
//        dto.setRoleIds(Lists.newArrayList(roleId));
//        dto.setIsDelete(Lists.newArrayList(Constants.IS_DELETE_NORMAL, Constants.IS_DELETE_YES));
//        List<RolePower> rs = rolePowerMapper.selectList(buildQueryWrapper(dto));
        List<RolePower> rolePowers;
        if (type == Constants.MENU_TYPE) {
//            需要删除的菜单权限集合
            rolePowers = rolePowerMapper.getPowersByRoleIdAndType(roleId, type);
        } else {
//            需要删除的按钮权限集合
            rolePowers = rolePowerMapper.getPowersByRoleIdAndTypetwo(roleId, type);
        }
        if (rolePowers == null) {
            log.info("RolePowerService.cleanBindRolePower({}) clean nothing", roleId);
            return;
        }

        cleanBindRolePowerWithRolePowerList(rolePowers);
    }

    private void cleanBindRolePowerWithRolePowerList(List<RolePower> rs) {
        if (rs == null || rs.isEmpty()) {
            return;
        }

        // 批量删除角色/权限/授权部门配置关系
        List<String> rolePowerIds = new ArrayList<>();
        for (RolePower r : rs) {
            rolePowerIds.add(r.getId());
        }
//        phyDeleteAuthDeptByRolePowerIds(rolePowerIds);

        // 批量删除角色权限关系
        if (!rolePowerIds.isEmpty()) {
            rolePowerMapper.deleteBatchIds(rolePowerIds);
        }

        // 清空用户角色缓存 + 权限缓存
        redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
        redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));
    }

    /**
     * 绑定角色权限关系
     *
     * @param req         MultiBindRolePowerReq
     * @param initUserDto InitUserDto
     */
    private void bindRolePowerAction(MultiBindRolePowerReq req, InitUserDto initUserDto) {
        for (String item : req.getPowers()) {
            RolePower rolePower = new RolePower();
            rolePower.setRoleId(req.getRoleId());
            Optional.ofNullable(item).ifPresent(rolePower::setPowerCode);
            addRolePowerUpdaterId(rolePower, initUserDto);
            boolean insert = save(rolePower);
            if (!insert) {
                log.error("RolePowerService.bindRolePowerAction(req = {}, initUserDto = {}) save( rolePower = {}) error", req, initUserDto, rolePower);
                throw new ApiException("绑定角色权限失败");
            }
        }

        // 清空用户角色缓存 + 权限缓存
        redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
        redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));
    }

    private QueryWrapper<RolePower> buildQueryWrapper(SearchRolePowerDto dto) {
        QueryWrapper<RolePower> q = new QueryWrapper<>();
        if (dto.getRoleIds() != null && !dto.getRoleIds().isEmpty()) {
            q.in("`role_id`", dto.getRoleIds());
        }

        if (dto.getPowerCodes() != null && !dto.getPowerCodes().isEmpty()) {
            q.in("`power_code`", dto.getPowerCodes());
        }

        if (dto.getIsDelete() != null && !dto.getIsDelete().isEmpty()) {
            q.in("`is_delete`", dto.getIsDelete());
        } else {
            q.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
        }

        return q;
    }

    /**
     * 批量物理删除授权部门id
     *
     * @param rolePowerIds List<String>
     */
    private void phyDeleteAuthDeptByRolePowerIds(List<String> rolePowerIds) {
        if (rolePowerIds == null || rolePowerIds.isEmpty()) {
            return;
        }

        QueryWrapper<PowerAuthDept> q = new QueryWrapper<>();
        q.in("role_power_id", rolePowerIds);
        q.eq(Constants.FIELD_KEY_IS_DELETE, Constants.IS_DELETE_NORMAL);
        List<PowerAuthDept> searches = powerAuthDeptMapper.selectList(q);
        if (searches == null) {
            return;
        }

        List<String> deleteIds = new ArrayList<>();
        for (PowerAuthDept search : searches) {
            deleteIds.add(search.getId());
        }

        // 物理删除
        if (!deleteIds.isEmpty()) {
            powerAuthDeptMapper.deleteBatchIds(deleteIds);
        }

        // 清空用户角色缓存 + 权限缓存
        redisService.deleteKeysWithPattern(AccountUtil.buildUserPowersKey("*"));
        redisService.deleteKeysWithPattern(AccountUtil.buildUserRolesKey("*"));
    }

    private void addRolePowerUpdaterId(RolePower rolePower, InitUserDto initUserDto) {
        if (initUserDto != null && initUserDto.getUserId() != null && !initUserDto.getUserId().isEmpty()) {
            rolePower.setUpdateId(initUserDto.getUserId());
        }
    }

    //查询所有菜单（树形）
    public List<PowerLevelResp> findAllList() {
        //      获取所有权限
        List<PowerLevelResp> list = roleMapper.getListByparent();
//        要返回的结果集
        List<PowerLevelResp> powers = new ArrayList<>();
//     存放一级目录
        for (PowerLevelResp powerLevelResp : list) {
            if (powerLevelResp.getParentId().equals("0")) {
                powers.add(powerLevelResp);
            }
        }
//    开始递归
        for (PowerLevelResp power : powers) {
            List<PowerLevelResp> pList = getChild(power.getId(), list);
            power.setChildren(pList);
        }

        return powers;
    }

    //  查询所有菜单递归
    private List<PowerLevelResp> getChild(String id, List<PowerLevelResp> power) {
        List<PowerLevelResp> childList = new ArrayList<>();
        for (PowerLevelResp powerItem : power) {
            // setChildren只存放菜单权限
            if (powerItem.getIsMenu() == 0) {
                continue;
            }
            if (powerItem.getParentId().equals(id)) {
                //当前父菜单拥有的按钮权限
                List<ButtonPowerResp> btnList = powerMapper.getButtonPowerList(powerItem.getId());
                powerItem.setBtns(btnList);
                childList.add(powerItem);
            }
        }
        for (PowerLevelResp entity : childList) {
            entity.setChildren(getChild(entity.getId(), power));
        }
        if (CollectionUtils.isEmpty(childList)) {
            return new ArrayList<>();
        }
        return childList;
    }

    /**
     * 查询角色拥有菜单递归
     *
     * @param id
     * @param power
     * @param powerIdList 角色拥有的所有权限集合
     * @return
     */
    private List<PowerLevelResp> getRoleByChild(String id, List<PowerLevelResp> power, List<String> powerIdList) {
        List<PowerLevelResp> childList = new ArrayList<>();

        for (PowerLevelResp powerItem : power) {
//            setChildren只存放菜单权限
            if (powerItem.getIsMenu() == 0) {
                continue;
            }
            if (powerItem.getParentId().equals(id)) {
//                判断是否拥有此菜单权限 0 拥有  1 没有
                if (powerIdList.contains(powerItem.getId())) {
                    powerItem.setChecked(0);
                } else {
                    powerItem.setChecked(1);
                }
//                当前父菜单拥有的按钮权限
                List<ButtonPowerResp> btnList = powerMapper.getButtonPowerList(powerItem.getId());

                List<ButtonPowerResp> btnsList = new ArrayList<>();
                for (ButtonPowerResp buttonPowerResp : btnList) {
                    // 判断是否拥有此按钮权限 0 拥有  1 没有
                    if (powerIdList.contains(buttonPowerResp.getId())) {
                        buttonPowerResp.setChecked(0);
                    } else {
                        buttonPowerResp.setChecked(1);
                    }
                    btnsList.add(buttonPowerResp);
                }
                powerItem.setBtns(btnsList);

                childList.add(powerItem);
            }
        }
        for (PowerLevelResp entity : childList) {
            entity.setChildren(getRoleByChild(entity.getId(), power, powerIdList));
        }
        if (CollectionUtils.isEmpty(childList)) {
            return new ArrayList<>();
        }
        return childList;
    }

    /**
     * list转换树
     * @param all 全部power
     * @param parents 父级power
     * @return
     */
    private  List<PowerLevelResp> powerLevelListToTree(List<PowerLevelResp> all, List<PowerLevelResp> parents)
    {
        List<PowerLevelResp> resp = new ArrayList<>();
        if(CollectionUtils.isEmpty(all) || CollectionUtils.isEmpty(parents)) return resp;
        resp.addAll(parents);
        for (PowerLevelResp powerLevelResp : resp) {
            List<PowerLevelResp> btns = all.stream().filter(x->x.getIsMenu().equals(0)&&x.getParentId().equals(powerLevelResp.getId())).collect(Collectors.toList());
            List<ButtonPowerResp> pageBtns = new ArrayList<>();
            for (PowerLevelResp btn : btns) {
                ButtonPowerResp b = new ButtonPowerResp();
                BeanHelper.copyProperties(btn,b);
                pageBtns.add(b);
            }
            powerLevelResp.setBtns(pageBtns);
            List<PowerLevelResp> child = all.stream().filter(x -> x.getParentId().equals(powerLevelResp.getId())).collect(Collectors.toList());
            powerLevelResp.setChildren(powerLevelListToTree(all,child));
        }
        return resp;
    }
}
